feat(server): next-page prefetch cache for paginated SELECT queries#391
feat(server): next-page prefetch cache for paginated SELECT queries#391
Conversation
Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
…yInternal Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
|
@copilot what can we do about these limitations? Ideally we should be able to cache any type of data including LOB types. Can we not keep them in memory as well ? It might ok to skip queries that receive a LOB as parameter, but as a return type in a query we should be able to cache it. |
Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Done in commit The only remaining skip is for queries that pass LOB session references as input parameters (BLOB/CLOB Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot some questions in relation to this implementation: |
…-page prefetch cache Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Both addressed in commit 1 - Cache isolation by datasource: Yes, it's now fully isolated. The cache key is 2 - Background cleanup job: A daemon Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot make sure there is only one background job that checks all cached objects, there is no need for multiple threads cleaning. |
…thread across all cache instances Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
|
@copilot create an integration test for Postgres with pagination. The test should create different amounts of records (99, 100, 101, 567(random), 1000 - make sure you use parameterized tests, not duplications) in a given table that contains multiple types and at least one LOB type. There should be tests paginating 100 records per page. You have to run a separate OJP server in the main CI workflow on a different port with pagination cache enabled and point the new integration test at this new server. You can use the same postgres db already present in the workflow, just name the table uniquely. Make sure all records are returned correctly when using cache and pagination, and assert every value. If a lob makes sure all bytes are returned correctly. |
Done in commit Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
… assertion Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
| */ | ||
| private static final ScheduledExecutorService CLEANUP_EXECUTOR = | ||
| Executors.newSingleThreadScheduledExecutor(r -> { | ||
| Thread t = new Thread(r, "ojp-prefetch-cache-cleanup"); |
There was a problem hiding this comment.
Fixed in commit 73a4d18. The thread factory now uses Thread.ofVirtual().name("ojp-prefetch-cache-cleanup").unstarted(r) instead of new Thread(r, ...). The explicit setDaemon(true) is no longer needed since virtual threads are always daemon threads. All 434 tests pass.
Done in commit New test class —
CI workflow —
Concern/note: PostgreSQL does not have a native |
…extPageCache.enabled) Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
You're right — there's no need for server-side per-datasource configuration for Fixed in # ojp.properties — client application
# Disable the prefetch cache for the "random-access" datasource
random-access.ojp.nextPageCache.enabled=falseThe server reads Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot implement similar pagination integration tests for all other databases supported. |
…achDB, DB2, Oracle, SQL Server, and H2 Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Done in
Each test paginates over 5 record counts (99, 100, 101, 567, 1000), asserts every column including byte-exact binary comparison, and is disabled by default (enabled via |
|
Tests failing MySQL and MariaDB Error: Errors: SQL server logs have errors like this tests are failing Error: Errors: |
…ache tests
MariaDB TINYINT(1) and SQL Server BIT are both mapped to Java Boolean by
their JDBC drivers. Calling rs.getInt() on these columns threw
NumberFormatException("false"). Changed both tests to use getBoolean()
with `id % 2 == 0`, consistent with PostgreSQL/H2/CockroachDB tests.
Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Fixed in MySQL/MariaDB: MariaDB's TINYINT(1) is mapped to Java SQL Server: SQL Server's |
rrobetti
left a comment
There was a problem hiding this comment.
Update the documentation as per now the configurations are in the client side instead of the server. Make sure that is the case on the integration tests.
…docs and tests for client-side config Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Fixed in Root cause of the gap: Changes:
|
.github/workflows/main.yml
Outdated
| rrobetti/ojp:0.4.1-SNAPSHOT | ||
|
|
||
| # Pagination-cache integration tests run against this server (port 10594) | ||
| - name: Start OJP Server container (prefetch cache on port 10594) |
There was a problem hiding this comment.
Do we still need a separated ojp server if now the nextPageCache is enabled in the client side per datasource?
There was a problem hiding this comment.
No — the separate server is no longer needed. Since the cache opt-in is now a client-side property (ojp.nextPageCache.enabled), the main OJP server is all that's needed. Fixed in 3a93056: the nextPageCache flags (enabled, ttlSeconds, prefetchWaitTimeoutMs) are moved to the main server in all 8 CI jobs, the ojp-server-prefetch-cache container is removed, and all 7 pagination-cache CSV files are updated from port 10594 → 1059.
.github/workflows/main.yml
Outdated
|
|
||
| # Start third OJP server WITH next-page prefetch cache enabled | ||
| # Pagination-cache integration tests run against this server (port 10594) | ||
| - name: Start OJP Server container (prefetch cache on port 10594) |
There was a problem hiding this comment.
Do we need a separated ojp server if nextPageCache is not enabled in the client side?
There was a problem hiding this comment.
No — a separate server is no longer needed. The main server has ojp.server.nextPageCache.enabled=true globally, and each client datasource opts in or out via ojp.nextPageCache.enabled in ojp.properties. The ojp-server-prefetch-cache container (port 10594) has been removed in 3a93056.
…e CSV ports and test docs Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
|
|
||
| | Property | Default | Description | | ||
| |---|---|---| | ||
| | `ojp.server.nextPageCache.enabled` | `false` | Enable/disable the feature globally | |
There was a problem hiding this comment.
What is this still talking about ojp.server configs, configs are no longer in the server, why dont you update everyhing? Review all changes in this PR and update
There was a problem hiding this comment.
Fixed in c0da110. All three documentation files have been updated to clearly reflect the two-tier model:
-
part2-chapter6-server-configuration.md: The "Configuration" section is rewritten as a two-step guide — Step 1 (server admin enables infra viaojp.server.nextPageCache.enabled=true) and Step 2 (client app opts each datasource in/out viaojp.nextPageCache.enabledinojp.properties). The "Per-Datasource Cache Control" subsection now only covers the server-sideprefetchWaitTimeoutMsper-datasource override (the only server setting that is still per-datasource). -
ojp-server-configuration.md: Removed the incorrect "No client changes are needed — the feature is entirely transparent" statement. Added a "Two-tier configuration model" callout box explaining the server/client split. -
NEXT_PAGE_PREFETCH_CACHE.md: "Quick Start" is now a two-step guide showing both server startup and the clientojp.propertiesconfiguration.
The server still owns the global toggle and resource tuning (ttlSeconds, maxEntries, etc.) — these affect server memory. The per-datasource enabled flag lives entirely on the client side.
…ss all three docs Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
|



getBoolean()for boolean columnsDatasourcePropertiesLoaderto forwardojp.nextPageCache.*properties to the serverojp.nextPageCache.enabled=trueto testojp.propertiesfor client-side demonstrationNEXT_PAGE_PREFETCH_CACHE.md— split config reference into server-side and client-side tables; add two-step Quick Start (server + client)ojp-server-configuration.md— remove incorrect "no client changes needed" statement; add two-tier model calloutpart2-chapter6-server-configuration.md— rewrite Configuration section as two-step guide (server infra + client per-datasource opt-in); simplify Per-Datasource sectionojp-server-prefetch-cacheCI container — addnextPageCacheflags to main server; update all 7 CSV files port 10594 → 1059📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.